package com.fs.uc.core.behavior;

import com.fs.uc.base.domain.*;
import com.fs.uc.base.exception.CustomException;
import com.fs.uc.base.repo.*;
import com.fs.uc.core.CacheName;
import io.quarkus.arc.log.LoggerName;
import io.quarkus.cache.*;
import org.jboss.logging.Logger;
import org.wildfly.common.Assert;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author 崔超
 * 2021/12/31
 */
@ApplicationScoped
@Transactional
class ParkBehaviorImpl implements ParkBehavior {
    @Inject
    OrgRepository orgRepo;
    @Inject
    PersonRepository personRepo;
    @Inject
    RoleRepository roleRepo;
    @Inject
    ModuleRepository moduleRepo;
    @Inject
    AdditionalRoleRepository additionalRoleRepo;

    @SuppressWarnings("CdiInjectionPointsInspection")
    @Inject
    CacheManager cacheManager;
    @LoggerName("ParkBehaviorImpl")
    Logger log;


    @Override
    public void create(String parkName, String loginName, String password, String managerPhone) {
        List<FunctionalModule> freeModules = moduleRepo.findFreeModules();
        Org org = new Org();
        org.name = parkName;
        org.loginName = loginName;
        org.password = password;
        org.type = OrgType.Park;
        org.functionalModules = new HashSet<>(freeModules);

        Person manager = createUserByPhone(managerPhone);
        org.leaders.add(manager);
        org.people.add(manager);

        orgRepo.persist(org);
    }

    @Override
    public void enableFunction(Long orgId, String moduleName) {
        FunctionalModule module = moduleRepo.findByName(moduleName);
        Assert.assertNotNull(module);
        Org park = orgRepo.getById(orgId);
        if (module.price > 0) {
            throw new CustomException("无法直接开通付费模块");
        }

        park.functionalModules.add(module);
        orgRepo.persist(park);
        //删除相关组织和人员的权限缓存
        clearCache(park);
    }


    @Override
    public void disableFunction(Long orgId, String moduleName) {
        FunctionalModule module = moduleRepo.findByName(moduleName);
        Assert.assertNotNull(module);
        Org park = orgRepo.getById(orgId);
        park.functionalModules.remove(module);
        orgRepo.persist(park);

        module.roles.stream()
                .filter(role -> role.type == RoleType.Additional)
                .forEach(role -> additionalRoleRepo.removeByOrgAndRole(orgId, role.id));

        //删除相关组织和人员的权限缓存
        clearCache(park);
    }

    @Override
    public Set<Role> getAssignableRoles(Long orgId) {
        Org park = orgRepo.getById(orgId);
        Set<Role> roleSet = new HashSet<>();

        for (FunctionalModule module : park.functionalModules) {
            for (Role role : module.roles) {
                if (role.type == RoleType.Additional) {
                    roleSet.add(role);
                }
            }
        }
        return roleSet;
    }

    @CacheInvalidate(cacheName = CacheName.PERSON_PERMISSION)
    @Override
    public void bindAdditionalRole(Long parkId, @CacheKey Long personId, List<String> roleNames) {
        additionalRoleRepo.removeByOrgUser(parkId, personId);

        List<Role> requestRoles = roleRepo.findByNames(roleNames);

        requestRoles.stream()
                .map(role -> role.id)
                .forEach(roleId -> {
                    AdditionalRole ar = new AdditionalRole(parkId, personId, roleId);
                    additionalRoleRepo.save(ar);
                });
    }

    private void clearCache(Org park) {
        List<Long> orgIds = park.children.stream().map(o -> o.id).collect(Collectors.toList());
        orgIds.add(park.id);
        List<Person> people = personRepo.findByCurrentOrgs(orgIds);

        cacheManager.getCache(CacheName.PERSON_PERMISSION).ifPresent(cache -> {
            for (Person p : people) {
                cache.invalidate(p.id).subscribe().with(
                        suc -> log.info(p.name + "清除权限缓存"),
                        fail -> log.error("清除权限缓存异常：" + fail)
                );
            }
        });
        cacheManager.getCache(CacheName.ORG_PERMISSION).ifPresent(cache ->
            cache.invalidate(park.id).subscribe().with(
                    suc -> log.info(park.name + "清除权限缓存"),
                    fail -> log.error("清除权限缓存异常：" + fail)
            )
        );
    }

    private Person createUserByPhone(String phone) {
        Person person = personRepo.findByPhone(phone);
        if (person == null) {
            person = new Person();
            person.phone = phone;
            personRepo.persist(person);
        }
        return person;
    }
}
